package com.bei.lingluan.slice;


import com.alibaba.fastjson.JSONObject;
import com.bei.lingluan.ResourceTable;
import com.bei.lingluan.listener.MyAsrListener;

import com.bei.lingluan.utils.HttpUtils;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.Operation;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.surfaceprovider.SurfaceProvider;
import ohos.agp.graphics.Surface;
import ohos.agp.graphics.SurfaceOps;
import ohos.agp.window.dialog.ToastDialog;
import ohos.ai.asr.AsrClient;
import ohos.ai.asr.AsrIntent;
import ohos.ai.asr.AsrListener;
import ohos.ai.asr.util.AsrResultKey;
import ohos.app.Context;
import ohos.app.dispatcher.TaskDispatcher;
import ohos.data.resultset.ResultSet;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.media.audio.AudioCapturer;
import ohos.media.audio.AudioCapturerInfo;
import ohos.media.audio.AudioStreamInfo;
import ohos.media.camera.CameraKit;
import ohos.media.camera.device.*;
import ohos.media.common.Source;
import ohos.media.common.StorageProperty;
import ohos.media.common.VideoProperty;
import ohos.media.image.ImageReceiver;
import ohos.media.image.common.ImageFormat;
import ohos.media.image.common.Size;
import ohos.media.photokit.metadata.AVStorage;
import ohos.media.recorder.Recorder;
import ohos.media.image.Image;
import ohos.utils.PacMap;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import static ohos.media.camera.device.Camera.FrameConfigType.*;

/**
 * @author 北海
 * @version 1.0
 * @description recording ability slice
 * @date 2022/2/11
 */
public class RecordingAbilitySlice extends AbilitySlice {
    private static final HiLogLabel TAG = new HiLogLabel(HiLog.LOG_APP,0, RecordingAbilitySlice.class.getSimpleName());
    private String cameraId,path;
    private ResultSet resultSet;
    // 相机预览模板
    private Surface previewSurface,recorderSurface;
    private SurfaceProvider surfaceProvider;
    // 接到图像输出设备并提供缓冲队列来接收图像数据的图像接收器
    private ImageReceiver imageReceiver;
    private EventHandler handler = new EventHandler(EventRunner.create("CameraCb"));
    private ohos.agp.components.Image takePhoto,goPlayBtn,exit;
    private Camera cameraDevice;
    private boolean flag = true;
    private boolean isRecording;
    private Object lock = new Object();
    private Recorder mediaRecorder;
    private CameraConfig.Builder cameraConfigBuilder;
    private DirectionalLayout surfaceContainer;
    private static final int SCREEN_WIDTH = 1080;
    private static final int SCREEN_HEIGHT = 1920;
    private static final int IMAGE_RCV_CAPACITY = 5;

    // 拍照支持分辨率
//    private Size pictureSize;

    private static final Map<String, Boolean> COMMAND_MAP = new HashMap<>();
    static {
        COMMAND_MAP.put("求救", true);
        COMMAND_MAP.put("报警", true);
        COMMAND_MAP.put("一", true);
    }
    private static AsrClient asrClient;
    private AudioCapturer audioCapturer;
    private boolean recognizeOver;
    private boolean isRecord = false;
    private ThreadPoolExecutor poolExecutor;


    private static final int EVENT_IMAGESAVING_PROMTING = 0x0000024;
    private static final int POOL_SIZE = 3;
    private static final int ALIVE_TIME = 3;
    private static final int CAPACITY = 6;
    private static final int SLEEP_TIME = 200;
    private static final int BYTES_LENGTH = 1280;
    private static final int VAD_END_WAIT_MS = 2000;
    private static final int VAD_FRONT_WAIT_MS = 4800;
    private static final int SAMPLE_RATE = 16000;
    private static final int TIMEOUT_DURATION = 20000;


    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_recording);


        initComponents();
        initSurface();
        initAudioCapturer();
        initAsrClient();
    }

    private void initComponents() {
        surfaceContainer = findComponentById(ResourceTable.Id_surface_container);
        takePhoto = findComponentById(ResourceTable.Id_recorder_btn);
        takePhoto.setClickedListener(this::takeSingleCapture);
        goPlayBtn = findComponentById(ResourceTable.Id_play_btn);
        goPlayBtn.setClickedListener(this::goPlayBtnFunc);
        exit = findComponentById(ResourceTable.Id_exit_btn);
        exit.setClickedListener((component -> terminateAbility()));
    }

    /**
     * 预览窗口初始化方法
     */

    private void initSurface() {
        getWindow().setTransparent(true);
        DirectionalLayout.LayoutConfig params = new DirectionalLayout.LayoutConfig(
                ComponentContainer.LayoutConfig.MATCH_PARENT, ComponentContainer.LayoutConfig.MATCH_PARENT);
        surfaceProvider = new SurfaceProvider(this);
        surfaceProvider.setLayoutConfig(params);
        surfaceProvider.pinToZTop(false);
        if (surfaceProvider.getSurfaceOps().isPresent()) {
            surfaceProvider.getSurfaceOps().get().addCallback(new SurfaceCallBack());
        }
        surfaceContainer.addComponent(surfaceProvider);
    }

    private void takeSingleCaptureInit(){
        // 获取拍照支持分辨率列表
//        List<Size> pictureSizes = cameraAbility.getSupportedSizes(ImageFormat.JPEG);
        // 根据拍照要求选择合适的分辨率
//        pictureSize = getPictureSize(pictureSizes);
        imageReceiver = ImageReceiver.create(SCREEN_WIDTH, SCREEN_HEIGHT, ImageFormat.JPEG, IMAGE_RCV_CAPACITY);
        imageReceiver.setImageArrivalListener(imageArrivalListener);

    }


    private void takeSingleCapture(Component component) {
        // 图像帧数据接收处理对象
        if (cameraDevice == null || imageReceiver == null) {
            return;
        }
        FrameConfig.Builder framePictureConfigBuilder = cameraDevice.getFrameConfigBuilder(FRAME_CONFIG_PICTURE);
        framePictureConfigBuilder.addSurface(imageReceiver.getRecevingSurface());
        FrameConfig pictureFrameConfig = framePictureConfigBuilder.build();
        cameraDevice.triggerSingleCapture(pictureFrameConfig);
    }

    // 单帧捕获生成图像回调Listener
    private final ImageReceiver.IImageArrivalListener imageArrivalListener = new ImageReceiver.IImageArrivalListener() {
        @Override
        public void onImageArrival(ImageReceiver imageReceiver) {

            StringBuffer fileName = new StringBuffer("picture_");
            fileName.append(UUID.randomUUID()).append(".jpg"); // 定义生成图片文件名
            File myFile = new File(getFilesDir(), fileName.toString()); // 创建图片文件
            ImageSaver imageSaver = new ImageSaver(imageReceiver.readNextImage(), myFile); // 创建一个读写线程任务用于保存图片
            handler.postTask(imageSaver); // 执行读写线程任务生成图片
        }
    };


    // 将图片传输到python flask搭建的服务端，使用训练好的pytorch模型进行识别
    class ImageSaver implements Runnable {
        private Image myImage;
        private File myFile;

        ImageSaver(Image image, File file) {
            myImage = image;
            myFile = file;
        }
        @Override
        public void run() {
            HttpUtils.sendImage(RecordingAbilitySlice.this,"http://beihai.free.idcfengye.com/test",myImage);
            String msg = "Take photo succeed, path=" + myFile.getPath();
            showTips(RecordingAbilitySlice.this, msg);
            myImage.release();
        }
    }


    /**
     * 视频播放方法
     * @param component
     */
    private void goPlayBtnFunc(Component component) {
        Intent intent = new Intent();
        Operation operation = new Intent.OperationBuilder()
                .withDeviceId("")
                .withBundleName("com.bei.lingluan")
                .withAbilityName("com.bei.lingluan.VideoPlayAbility")
                .build();
        intent.setOperation(operation);
        intent.setParam("path",path);
        startAbility(intent);
    }



    /**
     * 画布创建成功的回调方法
     */
    private class SurfaceCallBack implements SurfaceOps.Callback {
        @Override
        public void surfaceCreated(SurfaceOps callbackSurfaceOps) {
            if (callbackSurfaceOps != null) {
                //设置曲面的固定大小
                callbackSurfaceOps.setFixedSize(SCREEN_HEIGHT, SCREEN_WIDTH);
            }
            openCamera();
        }

        @Override
        public void surfaceChanged(SurfaceOps callbackSurfaceOps, int format, int width, int height) {
        }

        @Override
        public void surfaceDestroyed(SurfaceOps callbackSurfaceOps) {

        }
    }

    /**
     * 创建相机方法
     */
    private void openCamera() {
        takeSingleCaptureInit();
//        imageReceiver.setImageArrivalListener(this::saveImage);

        // 创建cameraKit对象
        CameraKit cameraKit = CameraKit.getInstance(getContext());
        // 获取逻辑摄像头
        try {
            // 获取当前设备的逻辑相机列表
            String[] cameraIds = cameraKit.getCameraIds();
            if (cameraIds.length <= 0) {
                HiLog.info(TAG,"相机设备为空");
                return;
            }
            // 选择第一个逻辑摄像头
            cameraId = cameraIds[0];
        } catch (IllegalStateException e) {
            HiLog.info(TAG,"获取逻辑摄像头失败");
        }
        // 一切准备就绪，开始创建camera
        if (cameraId != null && !cameraId.isEmpty()) {
            cameraKit.createCamera(cameraId, new CameraStateCallbackImpl(), handler);
        }
    }

    /**
     * 相机回调类
     */
    private class CameraStateCallbackImpl extends CameraStateCallback {

        @Override
        /**
         * 相机创建回调
         */
        public void onCreated(Camera camera) {

            // 获取画布
            if (surfaceProvider.getSurfaceOps().isPresent()){
                previewSurface = surfaceProvider.getSurfaceOps().get().getSurface();
            }
            if (previewSurface == null){
                return;
            }
            // 获取相机配置器
            CameraConfig.Builder cameraConfigBuilder = camera.getCameraConfigBuilder();
            // 相机配置器中增加预览的Surface
            cameraConfigBuilder.addSurface(previewSurface);
            // 配置拍照的Surface
            cameraConfigBuilder.addSurface(imageReceiver.getRecevingSurface());
            // 把新配置增加到相机中
            camera.configure(cameraConfigBuilder.build());
            cameraDevice = camera;
        }

        /**
         * 成功配置相机时调用
         * @param camera
         */
        @Override
        public void onConfigured(Camera camera) {
            // 提供帧捕获配置,获取预览配置模板
            FrameConfig.Builder framePreviewConfigBuilder = camera.getFrameConfigBuilder(FRAME_CONFIG_PREVIEW);
            // 配置预览surface和帧的绑定
            framePreviewConfigBuilder.addSurface(previewSurface);
            // 实现循环帧捕获
            camera.triggerLoopingCapture(framePreviewConfigBuilder.build());
        }
    }

    private void showTips(Context context, String msg) {
        getUITaskDispatcher().asyncDispatch(() -> new ToastDialog(context).setText(msg).show());
    }

    /**
     * 释放相机方法
     */
    private void releaseCamera() {
        if (cameraDevice != null) {
            cameraDevice.release();
            cameraDevice = null;
        }

        if (handler != null) {
            handler.removeAllEvent();
            handler = null;
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        releaseCamera();
    }

    private void openAudio() {
        HiLog.info(TAG, "openAudio");

        if (!isRecord) {
            // 开始读取和识别语音数据,AsrIntent为执行 ASR 引擎方法提供输入参数
            asrClient.startListening(setStartIntent());
            isRecord = true;
            poolExecutor.submit(new AudioCaptureRunnable());
        }
    }

    private void initAudioCapturer() {
        poolExecutor =
                new ThreadPoolExecutor(
                        POOL_SIZE,
                        POOL_SIZE,
                        ALIVE_TIME,
                        TimeUnit.SECONDS,
                        new LinkedBlockingQueue<>(CAPACITY),
                        new ThreadPoolExecutor.DiscardOldestPolicy());
        // 提供AudioCapturer和AudioRenderer的初始化参数
        AudioStreamInfo audioStreamInfo =
                new AudioStreamInfo.Builder()
                        .encodingFormat(AudioStreamInfo.EncodingFormat.ENCODING_PCM_16BIT)
                        .channelMask(AudioStreamInfo.ChannelMask.CHANNEL_IN_MONO)
                        .sampleRate(SAMPLE_RATE)
                        .build();

        // 提供录音所需的参数结构
        AudioCapturerInfo audioCapturerInfo = new AudioCapturerInfo.Builder().audioStreamInfo(audioStreamInfo).build();

        // 为应用程序提供接口以实现PCM录音和暂停功能
        audioCapturer = new AudioCapturer(audioCapturerInfo);
    }

    // 语音识别
    private boolean recognizeWords(String result) {
        JSONObject jsonObject = JSONObject.parseObject(result);
        JSONObject resultObject = new JSONObject();
        if (jsonObject.getJSONArray("result").get(0) instanceof JSONObject) {
            resultObject = (JSONObject) jsonObject.getJSONArray("result").get(0);
        }
        String resultWord = resultObject.getString("ori_word").replace(" ", "");
        boolean command = COMMAND_MAP.getOrDefault(resultWord, false);
        HiLog.info(TAG, "======" + resultWord + "===" + command);
        return command;
    }

    private void initListener() {
        // 用于观察 ASR 方法调用的过程和结果
        AsrListener asrListener = new MyAsrListener() {
            @Override
            public void onInit(PacMap params) {
                super.onInit(params);
                openAudio();
                HiLog.info(TAG, "======onInit======");
            }

            @Override
            public void onError(int error) {
                super.onError(error);
                HiLog.info(TAG, "======error:" + error);
            }

            // 当 ASR 引擎提供中间语音识别结果时调用
            @Override
            public void onIntermediateResults(PacMap pacMap) {
                super.onIntermediateResults(pacMap);
                HiLog.info(TAG, "======onIntermediateResults:");
                String result = pacMap.getString(AsrResultKey.RESULTS_INTERMEDIATE);
                boolean recognizeResult = recognizeWords(result);

                if (recognizeResult && !recognizeOver) {
                    recognizeOver = true;
                    takeSingleCapture(new Component(getContext()));
                    asrClient.stopListening();
                }
            }

            // 当 ASR 引擎提供最终解析的语音识别结果时调用
            @Override
            public void onResults(PacMap results) {
                super.onResults(results);
                HiLog.info(TAG, "======onResults:");

                recognizeOver = false;
                asrClient.startListening(setStartIntent());
            }

            @Override
            public void onEnd() {
                super.onEnd();
                HiLog.info(TAG, "======onEnd:");
                recognizeOver = false;
                asrClient.stopListening();
                asrClient.startListening(setStartIntent());
            }
        };

        // Initializes asr.
        if (asrClient != null) {
            asrClient.init(setInitIntent(), asrListener);
        }
    }

    private void initAsrClient() {
        // 提供用于调用自动语音识别 (ASR) 引擎服务的方法
        asrClient = AsrClient.createAsrClient(this).orElse(null);
        TaskDispatcher taskDispatcher = getAbility().getMainTaskDispatcher();
        taskDispatcher.asyncDispatch(
                new Runnable() {
                    @Override
                    public void run() {
                        initListener();
                    }
                });
    }

    private AsrIntent setInitIntent() {
        AsrIntent initIntent = new AsrIntent();
        initIntent.setAudioSourceType(AsrIntent.AsrAudioSrcType.ASR_SRC_TYPE_PCM);
        initIntent.setEngineType(AsrIntent.AsrEngineType.ASR_ENGINE_TYPE_LOCAL);
        return initIntent;
    }

    private AsrIntent setStartIntent() {
        AsrIntent asrIntent = new AsrIntent();
        asrIntent.setVadEndWaitMs(VAD_END_WAIT_MS);
        asrIntent.setVadFrontWaitMs(VAD_FRONT_WAIT_MS);
        asrIntent.setTimeoutThresholdMs(TIMEOUT_DURATION);
        return asrIntent;
    }

    private class AudioCaptureRunnable implements Runnable {
        @Override
        public void run() {
            byte[] buffers = new byte[BYTES_LENGTH];
            // 开始录音
            audioCapturer.start();
            while (isRecord) {
                // 从音频硬件读取音频数据
                int ret = audioCapturer.read(buffers, 0, BYTES_LENGTH);
                if (ret <= 0) {
                    HiLog.error(TAG, "======Error read data");
                } else {
                    // 将 PCM 音频流写入字节数组并执行语音识别
                    asrClient.writePcm(buffers, BYTES_LENGTH);
                }
            }
        }
    }

    @Override
    public void onActive() {
        super.onActive();
    }

    @Override
    public void onForeground(Intent intent) {
        super.onForeground(intent);
    }

}
